package com.itany.corejava.util;

import com.itany.corejava.constant.DateUtilConstant;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;

/**
 * @author 石小俊
 * @version 1.0
 * 日期工具类
 * @date 2023年04月28日 9:14
 */
public class DateUtil {

    /**
     * 将日期值转换成指定格式的字符串
     *
     * @param date    需要转换的日期值
     * @param pattern 指定的字符串格式
     * @return 转换后的字符串
     */
    public static String toString(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 将日期值转换成默认格式的字符串
     * 默认格式:yyyy-MM-dd HH:mm:ss
     *
     * @param date 需要转换的日期值
     * @return 转换后的字符串
     * @see DateUtilConstant
     */
    public static String toString(Date date) {
        return toString(date, DateUtilConstant.DATE_DEFAULT_PATTERN);
    }

    /**
     * 将一个指定格式的字符串转换成日期
     *
     * @param str     需要转换的字符串
     * @param pattern 指定字符串的格式
     * @return 转换后的日期值
     * @throws ParseException
     */
    public static Date toDate(String str, String pattern) throws ParseException {
        return new SimpleDateFormat(pattern).parse(str);
    }

    /**
     * 将一个默认格式的字符串转换成日期
     *
     * @param str 需要转换的字符串
     * @return 转换后的日期值
     * @throws ParseException
     * @see DateUtilConstant
     */
    public static Date toDate(String str) throws ParseException {
        return toDate(str, DateUtilConstant.DATE_DEFAULT_PATTERN);
    }

    /**
     * 获取指定日期的前一天
     *
     * @param date 指定日期
     * @return 返回指定日期的前一天
     * @see DateUtilConstant
     */
    public static Date getYesterday(Date date) {
        long time = date.getTime() - DateUtilConstant.ONE_DAY_MILLISECOND;
        return new Date(time);
    }

    /**
     * 获取指定日期的下一天
     *
     * @param date 指定日期
     * @return 返回指定的日期的下一天
     * @see DateUtilConstant
     */
    public static Date getNextDay(Date date) {
        long time = date.getTime() + DateUtilConstant.ONE_DAY_MILLISECOND;
        return new Date(time);
    }

    /**
     * 计算两个日期之间相差的天数
     * 不足一天的不计算
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 相差的整数天数
     * @see DateUtilConstant
     */
    public static int getDuringDay(Date startDate, Date endDate) {
        // 计算两个日期相差的毫秒数
        long time = endDate.getTime() - startDate.getTime();
        // 计算该毫秒数所代表的天数,只去整数天数,多余部分直接舍去
        int day = (int) (time / DateUtilConstant.ONE_DAY_MILLISECOND);
        return day;
    }

    /**
     * 计算两个日期之间相差的天数
     * 不足一天的算一天
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 相差的整数天数
     * @see DateUtilConstant
     */
    public static int getDuringDay2(Date startDate, Date endDate) {
        // 定义一个用于统计相差天数的变量
        int day = 0;
        // 只要startDate在endDate之前,即表示需要继续运算
        while (startDate.before(endDate)) {
            // 如果startDate在endDate之前
            // 取startDate的下一天,且day+1
            // 一直到startDate不再endDate之前
            startDate = getNextDay(startDate);
            day++;
        }
        return day;
    }

    /**
     * 获取指定日期中指定的年、月、日、时、分、秒的值
     *
     * @param date  指定的日期
     * @param field 指定需要获取哪一个部分的值
     * @return 返回指定部分的值
     * @see DateUtilConstant
     */
    public static int get(Date date, int field) {
        // 将一个日期转换成默认格式的字符串
        String s = toString(date);
        // 当前字符串格式为:yyyy-MM-dd HH:mm:ss
        // 将日期中表示年月日时分秒的值分别作为数组的一个元素进行存储
        // 此时可以将字符串分割成数组
        // 分割规则: 遇到短横杠、空格、冒号都进行分割
        // 可以使用正则表达式进行分割
        String[] arr = s.split("-|\\s|:");
        // System.out.println(Arrays.toString(arr));
        // 此时数组中存储的数据即为日期中每个部分的值
        // 而我们在常量接口中定义的常量值从0开始
        // 此时正好与数组下标重合
        return Integer.parseInt(arr[field]);
    }

    /**
     * 根据指定的年份与月份,获取这一年这个月共有多少天
     *
     * @param year
     * @param month
     * @return
     */
    public static int getDay(int year, int month) {
        // 将日期设置为year年month月的最后一天
        // 如果想要直接设置某个月的最后一天,不太好设置
        // 但是这一天的下一天一定是下个月的第一天
        // 即:下一个月的第一天的前一天即为这个月的最后一天
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        // month-1表示这个月,month-1+1表示下个月
        calendar.set(Calendar.MONTH, month);
        // 设置下个月的第一天的前一天
        // 第一天值为1,前一天即为1-1=0
        calendar.set(Calendar.DATE, 0);
        // 在这一天获取当前属于本月第几天,得到的值即为year年month月共有多少天
        return calendar.get(Calendar.DATE);
    }

    /**
     * 根据指定的年份与月份,获取这一年这个月共有多少天
     *
     * @param year
     * @param month
     * @return
     */
    public static int getDay2(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        // 设置日期的年份
        calendar.set(Calendar.YEAR, year);
        // 设置月份
        calendar.set(Calendar.MONTH, month - 1);
        // 获取year年month月天数的最大值
        return calendar.getActualMaximum(Calendar.DATE);
    }
}
